#region File Description
//-----------------------------------------------------------------------------
// InputState.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
#endregion

namespace Motoball
{
    /// <summary>
    /// Helper for reading input from keyboard and gamepad. This class tracks both
    /// the current and previous state of both input devices, and implements query
    /// properties for high level input actions such as "move up through the menu"
    /// or "pause the game".
    /// </summary>
    /// <remarks>Based on a similar class in the Game State Management sample.</remarks>
    public class InputState
    {
        #region Fields
        public const int MaxInputs = 4;

        public readonly KeyboardState[] CurrentKeyboardStates;
        public readonly GamePadState[] CurrentGamePadStates;

        public readonly KeyboardState[] LastKeyboardStates;
        public readonly GamePadState[] LastGamePadStates;

        public float[] RumbleTimer;
        public float[] RumbleTimerEnd;
        public float[,] RumbleValues;
        public bool[] IsRumbling;

        #endregion

        #region Initialization


        /// <summary>
        /// Constructs a new input state.
        /// </summary>
        public InputState()
        {
            CurrentKeyboardStates = new KeyboardState[MaxInputs];
            CurrentGamePadStates = new GamePadState[MaxInputs];

            LastKeyboardStates = new KeyboardState[MaxInputs];
            LastGamePadStates = new GamePadState[MaxInputs];

            IsRumbling = new bool[4];
            RumbleTimer = new float[4];
            RumbleTimerEnd = new float[4];
            RumbleValues = new float[4,2];
           
            for (int i = 0; i < 4; i++)
            {
                IsRumbling[i] = false;
                RumbleTimer[i] = 0;
                RumbleTimerEnd[i] = 0;
                for(int j=0; j<2; j++)
                    RumbleValues[i,j] = 0f;
            }
        }

        #endregion

        #region Properties



        public bool ButtonLeft
        {
            get
            {
                return IsNewKeyPress(Keys.Left) ||
                       IsNewButtonPress(Buttons.DPadLeft) ||
                       IsNewButtonPress(Buttons.LeftThumbstickLeft);
            }
        }

        public Vector2 LeftStick(int playerIndex)
        {
            return CurrentGamePadStates[playerIndex].ThumbSticks.Left;
        }

        public Vector2 RightStick(int playerIndex)
        {
            return CurrentGamePadStates[playerIndex].ThumbSticks.Left;
        }

        
        

        public bool ButtonRight
        {
            get
            {
                return IsNewKeyPress(Keys.Right) ||
                       IsNewButtonPress(Buttons.DPadRight) ||
                       IsNewButtonPress(Buttons.LeftThumbstickRight);
            }
        }

        public int MenuButtonPressed
        {
            get
            {
                if (ButtonLeft)
                    return 1;
                else if (ButtonRight)
                    return 2;
                else if (MenuSelect)
                    return 3;
                else if (MenuCancel)
                    return 4;
                else
                    return 0;
            }
        }

        /// <summary>
        /// Checks for a "menu select" input action, from any player,
        /// on either keyboard or gamepad.
        /// </summary>
        public bool MenuSelect
        {
            get
            {
                return IsNewKeyPress(Keys.Space) ||
                       IsNewKeyPress(Keys.Enter) ||
                       IsNewButtonPress(Buttons.A) ||
                       IsNewButtonPress(Buttons.Start);
            }
        }


        /// <summary>
        /// Checks for a "menu cancel" input action, from any player,
        /// on either keyboard or gamepad.
        /// </summary>
        public bool MenuCancel
        {
            get
            {
                return IsNewKeyPress(Keys.Escape) ||
                       IsNewButtonPress(Buttons.B) ||
                       IsNewButtonPress(Buttons.Back);
            }
        }


        /// <summary>
        /// Checks for a "exit game" input action, from any player,
        /// on either keyboard or gamepad.
        /// </summary>
        public bool ExitGame
        {
            get
            {
                return IsNewKeyPress(Keys.Escape) ||
                       IsNewButtonPress(Buttons.Back);
            }
        }


       


        #endregion

        #region Methods
        public void RumblePad(int playerIndex, float leftValue, float rightValue, float duration)
        {
            if (duration >= RumbleTimerEnd[playerIndex])
            {
                RumbleTimerEnd[playerIndex] += duration;
                IsRumbling[playerIndex] = leftValue != 0f || rightValue != 0f;
                if (leftValue > RumbleValues[playerIndex, 0])
                    RumbleValues[playerIndex, 0] = leftValue;
                if (rightValue > RumbleValues[playerIndex, 1])
                    RumbleValues[playerIndex, 1] = rightValue;

                GamePad.SetVibration((PlayerIndex)playerIndex, leftValue, rightValue);
            }
        }
        public void RumblePad(int playerIndex, float leftValue, float rightValue)
        {
            if (leftValue == 0f && rightValue == 0f)
                RumblePad(playerIndex, leftValue, rightValue, 0f);
            else
                RumblePad(playerIndex, leftValue, rightValue, 0.5f);
        }
        
        public void StopRumbling(int playerIndex)
        {
            if (playerIndex > 4)
                for (int i = 0; i < 4; i++)
                    StopRumbling(i);
            else
            {
                RumbleTimer[playerIndex] = 0;
                RumbleTimerEnd[playerIndex] = 0;
                RumbleValues[playerIndex, 0] = RumbleValues[playerIndex, 1] = 0;
                GamePad.SetVibration((PlayerIndex)playerIndex, 0, 0);
            }
        }
        public void PauseRumbling(bool pause)
        {
            for (int i = 0; i < 4; i++)
            {
                if (pause)
                    GamePad.SetVibration((PlayerIndex)i, 0, 0);
                else
                    GamePad.SetVibration((PlayerIndex)i, RumbleValues[i, 0], RumbleValues[i, 1]);

                IsRumbling[i] = !pause;
            }
        }

        /// <summary>
        /// Reads the latest state of the keyboard and gamepad.
        /// </summary>
        public void Update(GameTime gameTime)
        {
            for (int i = 0; i < MaxInputs; i++)
            {
                LastKeyboardStates[i] = CurrentKeyboardStates[i];
                LastGamePadStates[i] = CurrentGamePadStates[i];

                CurrentKeyboardStates[i] = Keyboard.GetState((PlayerIndex)i);
                CurrentGamePadStates[i] = GamePad.GetState((PlayerIndex)i);

                RumbleTimer[i] += (float)gameTime.ElapsedGameTime.TotalSeconds;
                if (RumbleTimer[i] > RumbleTimerEnd[i])
                {
                    StopRumbling(i);
                }
            }
        }


        /// <summary>
        /// Helper for checking if a key was pressed during this update,
        /// by any player.
        /// </summary>
        public bool IsKeyPress(Keys key)
        {
            for (int i = 0; i < MaxInputs; i++)
            {
                if (IsKeyPress(key, (PlayerIndex)i))
                    return true;
            }

            return false;
        }

       
        /// <summary>
        /// Helper for checking if a key was newly pressed during this update,
        /// by any player.
        /// </summary>
        public bool IsNewKeyPress(Keys key)
        {
            for (int i = 0; i < MaxInputs; i++)
            {
                if (IsNewKeyPress(key, (PlayerIndex)i))
                    return true;
            }

            return false;
        }

        public bool SplashScreenKeyPressed
        {
            get
            {
                return (IsNewKeyPress(Keys.Enter) || IsNewKeyPress(Keys.Space) ||
                    IsNewKeyPress(Keys.Escape));
            }
        }


        /// <summary>
        /// Helper for checking if a key was pressed during this update,
        /// by the specified player.
        /// </summary>
        public bool IsKeyPress(Keys key, PlayerIndex playerIndex)
        {
            return CurrentKeyboardStates[(int)playerIndex].IsKeyDown(key);
        }


        /// <summary>
        /// Helper for checking if a key was newly pressed during this update,
        /// by the specified player.
        /// </summary>
        public bool IsNewKeyPress(Keys key, PlayerIndex playerIndex)
        {
            return (CurrentKeyboardStates[(int)playerIndex].IsKeyDown(key) &&
                    LastKeyboardStates[(int)playerIndex].IsKeyUp(key));
        }


        /// <summary>
        /// Helper for checking if a button was pressed during this update,
        /// by any player.
        /// </summary>
        public bool IsButtonPress(Buttons button)
        {
            for (int i = 0; i < MaxInputs; i++)
            {
                if (IsButtonPress(button, (PlayerIndex)i))
                    return true;
            }

            return false;
        }


        /// <summary>
        /// Helper for checking if a button was newly pressed during this update,
        /// by any player.
        /// </summary>
        public bool IsNewButtonPress(Buttons button)
        {
            for (int i = 0; i < MaxInputs; i++)
            {
                if (IsNewButtonPress(button, (PlayerIndex)i))
                    return true;
            }

            return false;
        }


        /// <summary>
        /// Helper for checking if a button was pressed during this update,
        /// by the specified player.
        /// </summary>
        public bool IsButtonPress(Buttons button, PlayerIndex playerIndex)
        {
            return CurrentGamePadStates[(int)playerIndex].IsButtonDown(button);
        }


        /// <summary>
        /// Helper for checking if a button was newly pressed during this update,
        /// by the specified player.
        /// </summary>
        public bool IsNewButtonPress(Buttons button, PlayerIndex playerIndex)
        {
            return (CurrentGamePadStates[(int)playerIndex].IsButtonDown(button) &&
                    LastGamePadStates[(int)playerIndex].IsButtonUp(button));
        }


        /// <summary>
        /// Checks for a "menu select" input action from the specified player.
        /// </summary>
        public bool IsMenuSelect(PlayerIndex playerIndex)
        {
            return IsNewKeyPress(Keys.Space, playerIndex) ||
                   IsNewKeyPress(Keys.Enter, playerIndex) ||
                   IsNewButtonPress(Buttons.A, playerIndex) ||
                   IsNewButtonPress(Buttons.Start, playerIndex);
        }

        public bool A
        {
            get { return IsKeyPress(Keys.A); }
        }

        public bool D
        {
            get { return IsKeyPress(Keys.D); }
        }

        /// <summary>
        /// Checks for a "menu cancel" input action from the specified player.
        /// </summary>
        public bool IsMenuCancel(PlayerIndex playerIndex)
        {
            return IsNewKeyPress(Keys.Escape, playerIndex) ||
                   IsNewButtonPress(Buttons.B, playerIndex) ||
                   IsNewButtonPress(Buttons.Back, playerIndex);
        }

        #endregion
    }
}
